using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using OdsControllerLib;
using System.IO;
using System.Threading;


namespace ODSControllerService {
   public class ODS_Service : System.ServiceProcess.ServiceBase {

      FileSystemWatcher _fsw;

      string _appInstallPath; 
      string _appConfigFilename;
      string _appHostsFilename;
      string _serviceLogFilename;

      OdsClientObj _myclient;

      EventLog _eventLog;
      System.Timers.Timer _mainTimer;
      OdsMainObj _odsServerSettings;


      /// <summary> 
      /// Required designer variable.
      /// </summary>
      private System.ComponentModel.Container components = null;

      public ODS_Service() {
         // This call is required by the Windows.Forms Component Designer.
         InitializeComponent();




#if(DEBUG)
         Thread.Sleep(10000);
#endif

         //setup
         _appInstallPath = OdsMainObj.GetInstallPathFromRegistry();

         _appConfigFilename = Path.Combine(_appInstallPath, "config.xml");
         _appHostsFilename = Path.Combine(_appInstallPath, "hosts.xml");
         _serviceLogFilename = Path.Combine(_appInstallPath, "service.log");

         _odsServerSettings = new OdsMainObj(_appConfigFilename, _appHostsFilename, _serviceLogFilename, "Application", "ODS Controller Service");


         // setup service log
         this._eventLog.Log = _odsServerSettings.Log.LogEvent.EventLogName;
         this._eventLog.Source = _odsServerSettings.Log.LogEvent.EventLogSource;
         this.AutoLog = true;
#if(DEBUG)
         _odsServerSettings.Log.LogLevel = OdsLogLevel.Debug;
#else
            _odsServerSettings.Log.LogLevel = OdsLogLevel.Normal;
#endif

      }

      // The main entry point for the process
      static void Main() {
         System.ServiceProcess.ServiceBase[] ServicesToRun;

         // More than one user Service may run within the same process. To add
         // another service to this process, change the following line to
         // create a second service object. For example,
         //
         //   ServicesToRun = New System.ServiceProcess.ServiceBase[] {new Service1(), new MySecondUserService()};
         //
         ServicesToRun = new System.ServiceProcess.ServiceBase[] { new ODS_Service() };

         System.ServiceProcess.ServiceBase.Run(ServicesToRun);
         
      }

      /// <summary> 
      /// Required method for Designer support - do not modify 
      /// the contents of this method with the code editor.
      /// </summary>
      private void InitializeComponent() {
         this._eventLog = new System.Diagnostics.EventLog();
         this._mainTimer = new System.Timers.Timer();
         ((System.ComponentModel.ISupportInitialize)(this._eventLog)).BeginInit();
         ((System.ComponentModel.ISupportInitialize)(this._mainTimer)).BeginInit();
         // 
         // _mainTimer
         // 
         this._mainTimer.Interval = 60000;
         this._mainTimer.Elapsed += new System.Timers.ElapsedEventHandler(this._mainTimer_Elapsed);
         // 
         // ODS_Service
         // 
         this.ServiceName = "ODS Controller Service";
         ((System.ComponentModel.ISupportInitialize)(this._eventLog)).EndInit();
         ((System.ComponentModel.ISupportInitialize)(this._mainTimer)).EndInit();

         

      }

      /// <summary>
      /// Clean up any resources being used.
      /// </summary>
      protected override void Dispose(bool disposing) {
         if (disposing) {
            if (components != null) {
               components.Dispose();
            }
         }
         base.Dispose(disposing);
      }

      /// <summary>
      /// Set things in motion so your service can do its work.
      /// </summary>
      protected override void OnStart(string[] args) {
         try {


            //read settings file
            if (!_odsServerSettings.Settings.LoadFromXML()) {
               _odsServerSettings.Log.Write("Service not started.\n\nCould not read config file: " + _odsServerSettings.Settings.SettingsFile, LogCategories.ServiceEvents, DateTime.Now);
               this.OnStop();
               return;
            }

            //read hosts file
            if (!_odsServerSettings.Hosts.LoadFromXML()) {
               _odsServerSettings.Log.Write("Service not started.\n\nCould not read hosts file: " + _odsServerSettings.Hosts.HostsFile, LogCategories.ServiceEvents, DateTime.Now);
               this.OnStop();
               return;
            }



            string logstring = "Service started.\n";
            logstring += "\nUsername: " + _odsServerSettings.Settings.ServerUsername;
            logstring += "\nActive host count: " + _odsServerSettings.Hosts.CountActive.ToString();
            logstring += "\nUpdate interval: " + _odsServerSettings.Settings.UpdateInterval.ToString() + " minute(s)";


            if (_odsServerSettings.Settings.UpdateMethod == OdsUpdateMethod.WindowsServiceTimer && _odsServerSettings.Settings.UpdateInterval > 0) {
               _mainTimer.Interval = _odsServerSettings.Settings.UpdateInterval * 60000;
               _mainTimer.Enabled = true;
               _mainTimer.Start();
            }

            _odsServerSettings.Log.Write(logstring, LogCategories.ServiceEvents, DateTime.Now);

            

            _fsw = new FileSystemWatcher(Path.GetDirectoryName(_appConfigFilename), "*.xml");
            _fsw.Changed += new FileSystemEventHandler(_fsw_Changed);
            _fsw.EnableRaisingEvents = true;

         } catch (System.NullReferenceException e) {
            _odsServerSettings.Log.Write("Service failed to start.\nError: " + e.Message, LogCategories.ServiceEvents, DateTime.Now);
         }
      }

      void _fsw_Changed(object sender, FileSystemEventArgs e) {
         // wait for the file writes
         Thread.Sleep(5000);
         OnStop();
         OnStart(new string[]{});
      }

      /// <summary>
      /// Stop this service.
      /// </summary>
      protected override void OnStop() {
         // TODO: Add code here to perform any tear-down necessary to stop your service.
         _odsServerSettings.Log.Write("Service stopped.", LogCategories.ServiceEvents, DateTime.Now);
         _mainTimer.Enabled = false;
         _mainTimer.Stop();
      }

      protected override void OnPause() {
         _mainTimer.Enabled = false;
      }

      protected override void OnContinue() {
         _mainTimer.Enabled = true;
      }

      protected override void OnShutdown() {
         OnStop();
      }

      /// <summary>
      /// Method that actualy runs the update cycle
      /// </summary>
      /// <returns></returns>
      private bool RunUpdate() {
         try {
            if (_odsServerSettings.Settings.UpdateMethod != OdsUpdateMethod.WindowsServiceTimer)
               return false;

            _myclient = new OdsClientObj(_odsServerSettings.Settings, _odsServerSettings.Log);

            _odsServerSettings.Log.Write("Updating all hosts...", LogCategories.ServiceEvents, DateTime.Now);

            _myclient.Connect();
            _myclient.Login();

            foreach (OdsHostObj ohost in _odsServerSettings.Hosts) {
               // TODO: log host "name" bellow "All hosts updated."
               if (ohost.Active) _myclient.UpdateHost(ohost, false);
            }
            _myclient.Disconnect();

            _odsServerSettings.Log.Write("All hosts updated.", LogCategories.ServiceEvents, DateTime.Now);
         } catch (System.Exception e) {
            _odsServerSettings.Log.Write("Error: " + e.Message, LogCategories.ServiceEvents, DateTime.Now);
         }
         return true;
      }




      private void _mainTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
         this.RunUpdate();
      }
   }
}
